<template>
    <div class="welcome3">
        <div>
            <canvas id="myCanvas" :width="canvasWidth" :height="canvasHeight" style="border:1px solid #d3d3d3;">
                您的浏览器不支持 HTML5 canvas 标签。
            </canvas>
        </div>
        <div>
            <label>
                按回车生效
                <el-input placeholder="请输入内容" @keyup.enter.native="draw" v-model="text"></el-input>
            </label>
        </div>
    </div>

</template>

<script>

    import {getRandomColor} from "@/api/utils";

    export default {
        name: "welcome3",
        data(){
            return{
                ctx:null,//myCanvas对象
                canvasWidth:1000,//myCanvas宽
                canvasHeight:600,//myCanvas高
                text:'welcome',//文本
                size:200,//文本大小,
                textScale:0.85,//文本占canvas宽的比例
                ballSize:3,//小球半径
                ballSizeMax:4,//最大小球半径，一般为取像素步长的一半
                gridY:8,//取像素步长
                gridX:8,//取像素步长
                speedX:2,//小球在x轴上移动步长
                speedY:2,//小球在y轴上移动步长
                balls:[],//展示中小球数组
                newBalls:[],//将展示小球数组
                moveTimer:'',//循环执行对象，用于小球持续移动
                moveRate:125,//小球每秒移动次数
                twinkleTimer:'',//循环执行对象，用于小球持续闪烁
                twinkleRate:4,//小球每秒闪烁次数
                ballsMoving:false,//小球是否正在移动
            }
        },
        watch: {
            ballsMoving() {
                if (!this.ballsMoving) {
                    clearInterval(this.moveTimer);
                }
            }
        },
        methods:{
            init(){
                this.ctx = document.getElementById("myCanvas").getContext("2d");
                this.ctx.textAlign = "center";
                this.ctx.textBaseline = "bottom";
                this.ctx.font = this.size + "px arial";

                this.draw();
            },
            ball(x,y,color,size){
                this.x = x;
                this.y = y;
                this.color = color;
                this.size = size;
            },
            pushBalls(){
                var ball = null;
                var length = this.newBalls.length - this.balls.length;
                for (var i = 0; i < length; i++) {
                    if (Math.random() * 2 > 1){
                        ball = new this.ball(Math.random() * 2>1?1:this.canvasWidth-1,Math.floor(Math.random()*this.canvasHeight),getRandomColor(),Math.floor(Math.random()*this.ballSizeMax)+1);
                        this.balls.push(ball);
                    } else {
                        ball = new this.ball(Math.floor(Math.random()*this.canvasWidth),Math.random() * 2>1?1:this.canvasHeight-1,getRandomColor(),Math.floor(Math.random()*this.ballSizeMax)+1);
                        this.balls.push(ball);
                    }
                }
                for (length = this.balls.length - this.newBalls.length;length>0;length--){
                    this.balls.splice(Math.floor(Math.random()*this.balls.length),1);
                }
            },
            moveBalls(){
                this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight);
                var num = 0;
                for (var i = 0; i < this.newBalls.length; i++) {
                    if (this.newBalls[i].y !== this.balls[i].y || this.newBalls[i].x !== this.balls[i].x) {
                        num++;
                    }
                    if (this.newBalls[i].x > this.balls[i].x){
                        if (this.newBalls[i].x - this.balls[i].x > this.speedX) {
                            this.balls[i].x += this.speedX;
                        }else {
                            this.balls[i].x = this.newBalls[i].x;
                        }
                    } else if (this.newBalls[i].x < this.balls[i].x) {
                        if (this.balls[i].x - this.newBalls[i].x > this.speedX) {
                            this.balls[i].x -= this.speedX;
                        }else {
                            this.balls[i].x = this.newBalls[i].x;
                        }
                    }
                    if (this.newBalls[i].y > this.balls[i].y){
                        if (this.newBalls[i].y - this.balls[i].y > this.speedY) {
                            this.balls[i].y += this.speedY;
                        }else {
                            this.balls[i].y = this.newBalls[i].y;
                        }
                    } else if(this.newBalls[i].y < this.balls[i].y) {
                        if (this.balls[i].y - this.newBalls[i].y > this.speedY) {
                            this.balls[i].y -= this.speedY;
                        }else {
                            this.balls[i].y = this.newBalls[i].y;
                        }
                    }
                    this.ctx.beginPath();
                    this.ctx.fillStyle=this.balls[i].color;
                    this.ctx.arc(this.balls[i].x,this.balls[i].y,this.balls[i].size,0,2*Math.PI);
                    this.ctx.closePath();
                    this.ctx.fill();
                }
                if (num === 0) {
                    this.ballsMoving = false;
                    this.newBalls = [];
                }
            },
            animationFrame(){
                this.ballsMoving = true;
                this.moveTimer = setInterval(this.moveBalls,1000/this.moveRate);
                this.twinkleTimer = setInterval(this.twinkleBalls,1000/this.twinkleRate);
            },
            draw(){
                if (this.balls.length > 0) {
                    if (this.ctx.measureText(this.text).width/(this.canvasWidth*this.textScale)*this.size>=this.canvasHeight) {
                        this.$message({
                            message: 'Too many words',
                            type: 'error'
                        });
                        return;
                    }
                    if (this.ballsMoving) {
                        this.$message({
                            message: 'Moving!',
                            type: 'success'
                        });
                        return;
                    }
                }
                clearInterval(this.twinkleTimer);
                this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight);
                //画出原始文字
                this.canvasTextAutoLine(this.text,this.canvasWidth/2, this.canvasHeight/2+this.size/2,this.canvasWidth*this.textScale);
                let textData = this.ctx.getImageData(0,0,this.canvasWidth,this.canvasHeight);// 获取 canvas指定范围内的 像素数组
                let buffer32 = new Uint32Array(textData.data.buffer); // 转成32位的数组
                this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight);
                // 遍历所有的数组
                //const newImageData = this.ctx.createImageData(this.canvasWidth, this.canvasHeight);
                for (let j = 0; j < this.canvasHeight; j += this.gridY) {//步长
                    for (let i = 0; i < this.canvasWidth; i += this.gridX) {//步长
                        if (buffer32[j * this.canvasWidth + i]) {
                            /*newImageData.data[(j * this.canvasWidth + i)*4] = Math.floor(Math.random() * (256));
                            newImageData.data[(j * this.canvasWidth + i)*4+1] = Math.floor(Math.random() * (256));
                            newImageData.data[(j * this.canvasWidth + i)*4+2] = Math.floor(Math.random() * (256));
                            newImageData.data[(j * this.canvasWidth + i)*4+3] = 255;*/
                            // 放入粒子对象
                            var ball = new this.ball(i, j,getRandomColor(),Math.floor(Math.random()*this.ballSizeMax)+1);
                            this.newBalls.push(ball);
                        }
                    }
                }
                //this.ctx.putImageData(textData,0,0);
                this.pushBalls();
                this.animationFrame();

            },
            twinkleBalls(){
                this.ctx.clearRect(0,0,this.canvasWidth,this.canvasHeight);
                for (var i = 0; i < this.balls.length; i++) {
                    this.balls[i].size = Math.floor(Math.random()*this.ballSizeMax)+1;
                    this.ctx.beginPath();
                    this.ctx.fillStyle=this.balls[i].color;
                    this.ctx.arc(this.balls[i].x,this.balls[i].y,this.balls[i].size,0,2*Math.PI);
                    this.ctx.closePath();
                    this.ctx.fill();
                }
            },
            //在画布中画出文字，垂直居中，根据设置行宽lineWidthMax自动换行
            canvasTextAutoLine(text,initX,initY,lineWidthMax){
                let lineWidth = 0;
                let lastSubStrIndex = 0;
                let lineNumber = 0;
                //获得行数，以计算第一行y坐标
                for (let i = 0; i < text.length; i++) {
                    lineWidth += this.ctx.measureText(text[i]).width;
                    if (lineWidth > lineWidthMax) {
                        lineNumber++;
                        lineWidth = 0;
                        lastSubStrIndex = i;
                    }
                    if (i === text.length - 1) {
                        lineNumber++;
                    }
                }
                lineWidth = 0;
                lastSubStrIndex = 0;
                //第一行y坐标
                initY -= this.size / 2 * (lineNumber - 1);
                //一行一行画出文字
                for (let i = 0; i < text.length; i++) {
                    lineNumber++;
                    lineWidth += this.ctx.measureText(text[i]).width;
                    if (lineWidth > lineWidthMax) {
                        this.ctx.fillText(text.substring(lastSubStrIndex, i), initX, initY);
                        initY += this.size;
                        lineWidth = 0;
                        lastSubStrIndex = i;
                    }
                    if (i === text.length - 1) {
                        this.ctx.fillText(text.substring(lastSubStrIndex, i + 1), initX, initY);
                    }
                }
            }
        },
        mounted() {
            this.init();
        }
    }
</script>

<style scoped>

</style>
